package com.sloera.thread;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author sloera
 * @create 2020/4/25
 */
public class VolatileDemo {


    public static void main(String[] args) {
        noAutomaticByVolatile();
    }

    /*
     * volatile不保证原子性。
     * 使用automicInteger保证原子性
     */
    public static void noAutomaticByVolatile() {
        MyData myData = new MyData();
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    myData.addSelf();
                    myData.addAtomic();
                }
            }, String.valueOf(i)).start();
        }
        //需要等待上面20个线程全部计算完成后，再用main线程获取最终的结果值
        //main和gc线程
        while (Thread.activeCount() > 2) {
            Thread.yield();
        }
        System.out.println(Thread.currentThread().getName() + "\tfinally number is " + myData.number);
        System.out.println(Thread.currentThread().getName() + "\tfinally automic is " + myData.atomicInteger);
    }

    //volatile可以保证可见性，及时通知其它线程，主物理内存的值已经改变
    /*
     * @Description 验证volatile的可见性
     * 1.假如 int number = 0;number变量之前根本没有添加volatile关键字修饰，没有可见性
     * 2.添加volatile可以解决可见性问题
     * @param :
     * @Return void
     * @Author SloeraN
     * @Date 2020/4/25 14:59
     */
    public static void visiableByVolatile() {
        MyData myData = new MyData();//资源类
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\tcome in");
            //暂停一会线程
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myData.addTo60();
            System.out.println(Thread.currentThread().getName() + "\t update number value to " + myData.number);
        }, "AAA").start();

        // 第二个线程是main线程

        while (myData.number == 0) {
            // main 线程等待循环
        }
        // 无volatile时，执行不到此处
        System.out.println(Thread.currentThread().getName() + "\t 任务完成");
    }
}

class MyData {
    volatile int number = 0;

    public void addTo60() {
        this.number = 60;
    }

    //有volatile修饰，但不保证原子性
    public void addSelf() {
        number++;
    }

    AtomicInteger atomicInteger = new AtomicInteger();

    public void addAtomic() {
        atomicInteger.getAndIncrement();
    }
}